home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Java Programmer's Toolkit
/
Java Programmer's Toolkit.iso
/
applets
/
abacus
/
abacus~1.jav
< prev
next >
Wrap
Text File
|
1995-10-31
|
12KB
|
484 lines
/*
* Copyright (c) 1995 Luis Fernandes
*
* Permission to use, copy, hack, and distribute this software and its
* documentation for NON-COMMERCIAL purposes and without fee is hereby
* granted provided that this copyright notice appears in all copies.
*
*/
/* $Id: Abacus.java,v 1.3f 1995/06/01 22:59:31 elf Exp elf $ */
/* $Log: Abacus.java,v $
# Revision 1.3f 1995/06/01 22:59:31 elf
# Value of each column is now displayed in the top frame.
#
# Redraw (via update) is clipped to a region that surrounds the
# appropriate column that needs updating.
#
# Revision 1.2f 1995/04/17 16:40:13 elf
# Implemented user-defined resource "VALUE" which may to used to set
# the initial condition (bead-configuration) of the abacus.
#
# Eliminated *some* re-draw flicker by moving the repaint() call to
# animateBead() rather than keeping it in moveBead() where it caused
# the applet to redraw everytime a bead moved (this was especially bad
# when several beads moved at once).
# */
import java.awt.*;
/* This is a java-applet simulation of a Chinese abacus.
Each column is stored internally in an integer array called
'column' that is initialized to represent the resting positions of
the beads: 2 bead on top deck row-pos 0 & 1, pos 2 empty; 5 beads
lower deck pos 4-8, pos 3 empty. The initial value is
499d=111110011 where a '1' represents a position that is occupied
by a bead and a '0' represents an empty position. As the beads are
moved, the 1's are shifted (using << and >>) accordingly to
represent their new locations.
*/
/* The illustration below represents 1 column of the abacus.
* O represents the bead;
* | represents an empty position (the rod)
* = represents the frame
*
* ============= Row Position (index 'r' )
* O 0
* O 1 Upper Deck
* | 2
* =============
* | 3
* O 4
* O 5 Lower Deck
* O 6
* O 7
* O 8
* =============
*
*/
public class Abacus extends java.applet.Applet
{
/* initial attributes of the abacus*/
static final int MAXCOLS=10; /* number of columns the abacus will have */
static final int BEADHEIGHT=17;
static final int BEADWIDTH=17;
static final int FRAMEWIDTH=10; /* thickness of the frame*/
static final int COLGAP=2; /* gap between 2 cols*/
static final int ROWGAP=2; /* gap between 2 rows*/
static final int NTOPROWS=3; /*(2 beads, 1 gap on top-deck)*/
static final int NBOTROWS=6; /*(5 beads, 1 gap on top-deck)*/
static final int NCOLS=MAXCOLS; /* number of columns*/
static final int NROWS=(NTOPROWS+NBOTROWS); /* number of rows*/
static final int MIDFRAME=(FRAMEWIDTH+(NTOPROWS*BEADHEIGHT)+((NTOPROWS+1)*ROWGAP));
//size().width & size().height of window depends on attributes of the abacus
static final int INITWIDTH=((2*FRAMEWIDTH)+(NCOLS*BEADWIDTH)+((NCOLS+1)*COLGAP));
static final int INITHEIGHT=((3*FRAMEWIDTH)+(NROWS*BEADHEIGHT)+((NROWS+1)*ROWGAP));
private int column[]=new int[MAXCOLS];
private int cx, cy; // for xlating x,y to row,col
private int ux, uy; // for clipping region
private boolean overflow; // when the abacus overflows this is true
private boolean carry; // when a calc causes a carry to the next col
Image bead, nobead; // holds picture of a bead and an empty loc
Font valueFont; // to paint the value
public
void init()
{
String valattr;
/* Init the internal configuration of the beads: 499d=111110011
* (2 bead on top deck pos 0 & 1; 5 beads lower deck pos 4-8,
* pos 2 & 3 are empty initially) */
for(int i=0; i<MAXCOLS; i++) column[i]=499;
/* check for user-specified value resource*/
valattr=getParameter("value");
/* System.out.println("==>"+valattr); */
if((valattr==null) || (valattr.length()>MAXCOLS) )
{
/* if no attribute is specified, or the value is too big,
* use default*/
System.out.println(valattr+"(VALUE resource) is either too big or unspecified; ignoring.\n");
}
else /* set each column according to the user-specified value*/
{
int len=valattr.length();
for(int i=0; i<len; i++)
{
int val=Integer.valueOf(valattr.substring(i,i+1)).intValue();
// set value in the upper-deck
if(val>4)
{
/* System.out.println("Col "+i+"%5="+val%5); */
animateBead(1, i);
}
// set value in the lower-deck
int remainder=val%5;
if(remainder>0)
{
animateBead(3+remainder, i);
}
}
}
bead=getImage(getCodeBase(), "images/diamond.gif");
nobead=getImage(getCodeBase(), "images/nodiamond.gif");
valueFont=new java.awt.Font("Courier", Font.BOLD, 10);
resize(INITWIDTH, INITHEIGHT); /* initial size */
}
private
void displayValue(Graphics g)
{
char valchars[]= new char [MAXCOLS*3];
String value= new String (valchars);
if(overflow) value+="*";
/* look at each column*/
for(int col=0; col<MAXCOLS; col++)
{
int r;
int val=0;
/* find the empty row, and determine what the value is*/
/* top-deck*/
for(r=2; r>=0; r--)
{
if(!RowOccupied(r, column[col])) break;
}
val+=((2-r)*5);
/* bottom-deck*/
for(r=3; r<9; r++)
{
if(!RowOccupied(r, column[col])) break;
}
val+=(r-3);
/* System.out.println("\tColumn"+col+"value="+val);*/
value=value+" "+Integer.toString(val);
}
if(overflow)
g.setColor(Color.red);
else
g.setColor(Color.yellow);
g.drawString(value, 5, 10);
}
/* draw the abacus */
public
void paint(Graphics g)
{
if (bead == null) {
return;
}
drawFrame(g);
for(int i=0; i<MAXCOLS; i++)
{
drawColumn(g, i);
}
displayValue(g);
}/* init()*/
public void update(Graphics g)
{
paint(g);
g.setColor(Color.black);
g.fillRect(0,0,INITWIDTH, FRAMEWIDTH);
displayValue(g);
}
public
boolean mouseUp(java.awt.Event evt, int x, int y) {
/* row,col returned in cx,cy*/
boolean i=translateXY2RowCol(x, y);
if(i) /*valid row,col...*/
{
if(RowOccupied(cy,column[cx]))
{
animateBead(cy,cx);
ux=FRAMEWIDTH+(cx*(COLGAP+BEADWIDTH));
uy=FRAMEWIDTH+(cy*(ROWGAP+BEADHEIGHT));
repaint();
}
}
return true;
} /*mouseUp()*/
private
void drawColumn(Graphics g, int col)
{
for(int beadnum=0; beadnum<9; beadnum++)
{
if(RowOccupied(beadnum,column[col]))
{
drawBead(g, beadnum, col);
}
else
{
undrawBead(g, beadnum, col);
}
}
} /*drawColumn()*/
private
void drawBead(Graphics g, int row, int col)
{
if(row<3) /* beads in the top-deck */
{
g.drawImage(bead, FRAMEWIDTH+COLGAP+(col*(BEADWIDTH+COLGAP)),
FRAMEWIDTH+(row*(BEADHEIGHT+ROWGAP))+2, this);
}
else /* account for the middle-rail */
{
g.drawImage(bead, FRAMEWIDTH+COLGAP+(col*(BEADWIDTH+COLGAP)),
(2*FRAMEWIDTH)+(row*(BEADHEIGHT+ROWGAP))+2, this);
}
} /*drawBead()*/
private
void undrawBead(Graphics g, int row, int col)
{
if(row<3) /* beads in the top-deck */
{
g.drawImage(nobead, FRAMEWIDTH+COLGAP+(col*(BEADWIDTH+COLGAP)),
FRAMEWIDTH+(row*(BEADHEIGHT+ROWGAP))+2, this);
}
else /* account for the middle-rail */
{
g.drawImage(nobead, FRAMEWIDTH+COLGAP+(col*(BEADWIDTH+COLGAP)),
(2*FRAMEWIDTH)+(row*(BEADHEIGHT+ROWGAP))+2, this);
}
} /*undrawBead()*/
private
void drawFrame(Graphics g)
{
g.setColor(Color.blue);
/* the rails*/
for(int i=0; i<NCOLS; i++)
g.drawLine(FRAMEWIDTH+COLGAP+(BEADWIDTH/2)+(i*(BEADWIDTH+COLGAP)), 0,
FRAMEWIDTH+COLGAP+(BEADWIDTH/2)+(i*(BEADWIDTH+COLGAP)),
INITHEIGHT);
g.setColor(Color.black);
g.fillRect(0,0,INITWIDTH, FRAMEWIDTH); /*top bar*/
g.fillRect(0,INITHEIGHT-FRAMEWIDTH, INITWIDTH, FRAMEWIDTH); /*bot bar*/
g.fillRect(INITWIDTH-FRAMEWIDTH, 0, INITWIDTH, INITHEIGHT); /*right bar*/
g.fillRect(0,0, FRAMEWIDTH, INITHEIGHT-FRAMEWIDTH); /*left bar*/
/* middle bar*/
g.fillRect(0, MIDFRAME, INITWIDTH, FRAMEWIDTH);
}/*drawFrame()*/
public
void animateBead(int r, int c)
{
if(r<3) /* selection in upper deck*/
{
int i;
/* find empty row in upperdeck; pos 0,1,2*/
for(i=0; i<3; i++) if(!RowOccupied(i,column[c])) break;
if(i<r) /* if empty row is above cur bead...*/
moveBeadUp(r,c);
else
moveBeadDn(r,c);
}
else /* selection in lower deck*/
{
int i;
/* find empty row in lowerdeck; pos 3-8 */
for(i=3; i<9; i++) if(!RowOccupied(i,column[c])) break;
if(i<r) /* if empty row is above cur bead...*/
moveBeadUp(r,c);
else
moveBeadDn(r,c);
}
}/*animateBead()*/
private
void moveBeadUp(int r, int c)
{
/* keep looking for an empty position directly above*/
if(RowOccupied(r-1,column[c])) moveBeadUp(r-1,c);
column[c]=column[c]-(1<<r); /* row 'r' is now empty */
column[c]=column[c]+(1<<((r-1))); /* row 'r-1' now is occupied*/
// check whether we have to carry to next column
if(!RowOccupied(0,column[c]))
{
System.out.println("Carry to col"+(c-1));
carry=true;
}
else if(c==0 && r==1)
{
overflow=false;
}
} /*moveBeadUp()*/
private
void moveBeadDn(int r, int c)
{
/* keep looking for an empty position directly below*/
if(RowOccupied(r+1,column[c])) moveBeadDn(r+1,c);
column[c]=column[c]-(1<<r); /* row 'r' is now empty */
column[c]=column[c]+(1<<((r+1))); /* row 'r+1' now is occupied*/
// check whether we have to carry to next column if in the top frame
if(!RowOccupied(0,column[c]) && r<3)
{
if(c==0)
{
System.out.println("***OVERFLOW***");
overflow=true;
return;
}
System.out.println("Carry to col"+(c-1));
carry=true;
}
}/* moveBeadDown()*/
/* ///////////////Misc Functions///////////////////////*/
/* translateXY2RowCol, converts x,y coord a row,col coord. The top
* deck has 3 rows (1 is empty), the bottom deck has 6 rows (1 is
* empty). Row # 3 is invalid because the middle-frame occupies this
* position. Coordinates for the bottom deck are adjusted for this
* anomaly, i.e. row #4 on the screen, is actually index #3 into the
* Column array.
*
* passed: (pointers to) absolute x,y coordinates representing
* the click-location
* returns: - as globals cx, cy, the row (0-9), col (0-NCOLS)
* index
* - True if click was on a bead or empty position
* - False if click was at mid-frame location
*/
private
boolean translateXY2RowCol(int x, int y)
{
cx=(x-FRAMEWIDTH)/(COLGAP+BEADWIDTH);
if(cy<MIDFRAME)
{
cy=(y-FRAMEWIDTH)/(ROWGAP+BEADHEIGHT);
}
else /* account for the middle-frame (+1 bead size().height) (+4 is fudge)*/
{
cy=(y-((2*FRAMEWIDTH)-BEADHEIGHT))/(ROWGAP+BEADHEIGHT);
}
/* technically, the mid-frame occupies position 3 & click is invalid*/
if(cy==3) return(false);
else if(cy>2) /* if pos (row) is greater than 3 ...*/
{
cy--; /* ...adjust by 1 row*/
return(true);
}
else
{
return(true);
}
}/*translateXY2RowCol()*/
final private
boolean RowOccupied(int r, int c)
{
if((c & 1<<(r))==0)
{
return false;
}
else
{
return true;
}
}/*RowOccupied()*/
}